package pojo;

import soot.Scene;
import tuple.data.DataKind;
import tuple.entity.MyEntity;
import soot.SootClass;
import soot.SootMethod;
import soot.jimple.Stmt;
import soot.jimple.infoflow.results.DataFlowResult;
import soot.jimple.infoflow.results.ResultSinkInfo;
import soot.jimple.infoflow.results.ResultSourceInfo;
import soot.jimple.infoflow.solver.cfg.IInfoflowCFG;
import util.FlowdroidUtils;

import java.util.*;
import java.util.stream.Collectors;

public class MyDataFlowResult extends DataFlowResult {
    //    private final IInfoflowCFG cfg;
    public final Stmt[] stmts;
    public final List<SootMethod> methodList;
    public final List<SootClass> clazzList;
    //    public final List<MyCallsite> callsites;
    // 保存数据流分析结果的字段
    private final Set<MyEntity> entitySet;
    private final Set<DataKind> dataSet;
    private final Set<String> permission;

    public MyDataFlowResult(ResultSourceInfo source, ResultSinkInfo sink, IInfoflowCFG cfg) {
        super(source, sink);
        List<SootMethod> methodList1;
//        List<MyCallsite> callsites1;
        List<SootClass> clazzList1;

        // getPath是获取整个调用链; 而getPathCallSites 是 getPath的返回做个过滤；长度不变，非调用语句全部变成null；容易出bug
        this.stmts = super.getSource().getPath();
        try {
            methodList1 = Arrays.stream(stmts).map(cfg::getMethodOf).collect(Collectors.toList());
            clazzList1 = Arrays.stream(stmts).map(s -> cfg.getMethodOf(s).getDeclaringClass()).collect(Collectors.toList());
//            callsites1 = Arrays.stream(stmts).map(stmt -> new MyCallsite(stmt, cfg.getMethodOf(stmt))).collect(Collectors.toList());
        } catch (RuntimeException re) {
            methodList1 = new ArrayList<>();
            methodList1.add(cfg.getMethodOf(source.getStmt()));
            methodList1.add(cfg.getMethodOf(sink.getStmt()));
            clazzList1 = methodList1.stream().map(SootMethod::getDeclaringClass).collect(Collectors.toList());
        }
        for (SootMethod sm:methodList1){
            try{
                Scene.v().loadClass(sm.getDeclaringClass().getName(),SootClass.BODIES);
                FlowdroidUtils.forceLoadBody(sm);
            }
            catch (Exception e){
            }
        }

        // 保存数据流分析结果的字段
        this.clazzList = clazzList1;
        this.methodList = methodList1;
        this.entitySet = new HashSet<>();
        this.dataSet = new HashSet<>();
        this.permission = new HashSet<>();
    }


    public List<SootMethod> getMethodList() {
        return methodList;
    }


    public Set<MyEntity> getEntitySet() {
        return entitySet;
    }

    public Set<DataKind> getDataSet() {
        return dataSet;
    }

    public Set<String> getPermission() {
        return permission;
    }
}
